#include "include/Session.h"
#include "include/Configuration.h"
#include "include/Singleton.h"

Logic::Logic()
{
}

Logic::~Logic()
{
}

void Logic::Init()
{
	_dll_manager.Init();
}

int Logic::ProcessData(int thread_id, char *buf, int len)
{
	int data_len;
	char* data_buf;

	if(ParseHead(buf, len))
	{
		// debug
		std::cout << "process data error 1" << std::endl;
		// debug end
		FillErrorData(ErrHeadError, buf, len);
		return Common::NormalData;
	}

	if(_dll_manager.LoadDll(thread_id))
	{
		// debug
		std::cout << "process data error 2" << std::endl;
		// debug end
		FillErrorData(ErrDllLoadError, buf, len);
		return Common::NormalData;
	}

	if(_dll_manager.Do(thread_id, buf, &len))
	{
		// debug
		std::cout << "process data error 3" << std::endl;
		// debug end
		FillErrorData(ErrDataProcessError, buf, len);
		return Common::NormalData;
	}

	return GetPackageNum(buf, len);
}

int Logic::GetPackageNum(char *buf, int len)
{
	_package_head_list.clear();
	_package_len_list.clear();

	struct Common::PackageHead *p_head = PackageUtil::GetPackageHead(buf);

	_package_head_list.push_back((char *)p_head);
	_package_len_list.push_back(PackageUtil::GetPackageLen((char *)p_head));

	while(1 == p_head->multi_data)
	{
		p_head = PackageUtil::GetNextPackageHead(p_head);

		if((char *)p_head - buf > len)
		{
			break;
		}

		switch((enum Common::DataType)p_head->append_data)
		{
			case Common::DelayData:
			case Common::DelayUpData:
			case Common::DelayBroadcastData:
			case Common::DelayMulticastData:
				_package_head_list.push_back((char *)p_head);
				_package_len_list.push_back(sizeof(struct Common::PackageHead) + p_head->length);
				break;

			default:
				_package_len_list[_package_len_list.size() - 1] += PackageUtil::GetPackageLen((char *)p_head);
				break;
		}
	}

	RegroupPackage();

	return _package_head_list.size();
}

void Logic::RegroupPackage()
{
	for(int i = 0; i < _package_head_list.size(); i++)
	{
		SetPackageMultiDataFlag(_package_head_list[i], _package_len_list[i]);
	}
}

void Logic::SetPackageMultiDataFlag(char *buf, int len)
{
	struct Common::PackageHead *p_head = PackageUtil::GetPackageHead(buf);
	int package_len = PackageUtil::GetPackageLen(buf);

	while(package_len < len)
	{
		len -= package_len;
		p_head = PackageUtil::GetNextPackageHead(p_head);
		package_len = PackageUtil::GetPackageLen((char *)p_head);
	}

	p_head->multi_data = 0;
}

enum Common::DataType Logic::ProcessDownStreamPackage(int index, char *&p_data, int &len)
{	
	if((unsigned int)index >= _package_head_list.size())
	{
		return Common::EmptyData;
	}

	if(ParseHead(_package_head_list[index]))
	{
		// debug
		std::cout << "error 2" << std::endl;
		// debug end
		return Common::EmptyData;
	}

	drop_info_len = 0;
	p_data = _package_head_list[index];
	//len = PackageUtil::GetPackageLen(p_data);
	len = _package_len_list[index];
	Common::PackageHead *p_package_head = PackageUtil::GetPackageHead(p_data);

	switch((enum Common::DataType)p_package_head->append_data)
	{
		case Common::DelayData:
		case Common::DelayUpData:
		case Common::DelayBroadcastData:
		{
			Common::DelayHead *p_delay_head = PackageUtil::GetDelayHead(p_data);
			delay_ms = p_delay_head->delay_ms;

			drop_info_len = sizeof(struct Common::DelayHead);
			PackageUtil::GetPackageHead(p_data)->length -= drop_info_len;
		}
			break;

		case Common::DelayMulticastData:
		{
			Common::DelayHead *p_delay_head = PackageUtil::GetDelayMulticastHead(p_data);
			delay_ms = p_delay_head->delay_ms;

			drop_info_len = sizeof(struct Common::DelayHead);
			PackageUtil::GetPackageHead(p_data)->length -= drop_info_len;
		}
			break;

		default:
			break;
	}

	return (Common::DataType)p_package_head->append_data;
}

int Logic::ParseHead(char * buf, int len)
{
	if(len > 0 && len < sizeof(Common::PackageHead))
	{
		cout << "len error: " << len << " in PareHead" << endl; 
		return 1;
	}

	struct Common::PackageHead *p_head = PackageUtil::GetPackageHead(buf);

	if(p_head->protocol != Singleton<Configuration>::instance().protocol)
	{
		cout << "protocol error: " << p_head->protocol << " in PareHead" << endl; 
		return 1;
	}

	if(p_head->version != Singleton<Configuration>::instance().version)
	{
		cout << "version error: " << p_head->version << " in PareHead" << endl; 
		return 1;
	}

	if(0 == p_head->player_id && p_head->append_data != Common::MulticastData &&
		p_head->append_data != Common::DelayMulticastData)
	{
		cout << "player_id error: " << p_head->player_id << " in PareHead" << endl; 
		return 1;
	}

	return 0;
}

void Logic::FillErrorData(enum ErrorNo  error_no, char *buf, int &len)
{
}
